using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using SharpObjects.Configuration;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.Interfaces;

namespace SharpObjects.Data
{
    public class SqlServerDb : IDb, IXmlInitializable 
    {
        private SqlConnection connection = null;
        private string connectionString = null;
        private SqlTransaction transaction = null;


        #region IDb Members

        public string Id { get; set; }

        public string DatabaseBrandAndVersion
        {
            get { return "sql_server"; }
        }

        public System.Data.IDbCommand CreateQueryCommand(string sql)
        {
            SqlCommand cmd = new SqlCommand(sql, this.connection, this.transaction);
            return cmd;
        }

        public System.Data.IDbCommand CreateQueryCommand(string sqlTemplate, string parameterDescriptorXml, params object[] values)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbCommand CreateQueryCommand(string sqlTemplate, params IDbParameter[] dbParameters)
        {
            string sql = string.Format(sqlTemplate, GetParamNames(dbParameters));
            SqlCommand command = new SqlCommand(sql, this.connection, this.transaction);
            command.CommandType = CommandType.Text; // default

            foreach (IDbParameter dbParameter in dbParameters)
            {
                if (!dbParameter.IsDirectSqlExpression)
                {
                    SqlParameter par = new SqlParameter();
                    par.ParameterName = this.ParameterPrefix + dbParameter.ParameterName;
                    par.SqlDbType = DataTypeToSqlDbType(dbParameter.DataType);
                    par.Size = dbParameter.Size;
                    par.SourceColumn = parameter_prefix + dbParameter.SourceColumn;
                    par.Direction = dbParameter.Direction;
                    par.Precision = dbParameter.Precision;
                    par.Scale = dbParameter.Scale;
                    par.SourceVersion = dbParameter.SourceVersion;
                    par.Value = dbParameter.Value;

                    command.Parameters.Add(par);
                }
            }

            return command;
        }

        public System.Data.IDbCommand CreateQueryCommand(string sqlTemplate, System.Collections.Generic.List<IDbParameter> parameters)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbCommand CreateProcedureCommand(string procedureName, string parameterDescriptorXml, params object[] values)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbCommand CreateProcedureCommand(string procedureName, params IDbParameter[] parameters)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbCommand CreateProcedureCommand(string procedureName, System.Collections.Generic.List<IDbParameter> parameters)
        {
            throw new System.NotImplementedException();
        }

        public void SetCommandParameterValue(System.Data.IDbCommand command, int parameterIndex, object value)
        {
            throw new System.NotImplementedException();
        }

        public void SetCommandParameterValue(System.Data.IDbCommand command, string parameterName, object value)
        {
            throw new System.NotImplementedException();
        }

        public IProcedureDescriptor ParseProcedureDefinitionSql(string procedureDefinitionSql)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbCommand CreateProcedureCommand(IProcedureDescriptor procedureDescriptor)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbDataAdapter CreateDataAdapter(string selectStatement)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbDataAdapter CreateDataAdapter(string selectStatement, bool generateAllCommands)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbDataAdapter CreateDataAdapter(System.Data.IDbCommand selectCommand)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbDataAdapter CreateDataAdapter(System.Data.IDbCommand selectCommand, bool generateAllCommands)
        {
            throw new System.NotImplementedException();
        }

        public void SetDataAdapterUpdateBatchSize(System.Data.IDbDataAdapter dataAdapter, int batchSize)
        {
            throw new System.NotImplementedException();
        }

        public int ExecuteNonQuery(System.Data.IDbCommand command)
        {
            throw new System.NotImplementedException();
        }

        public object ExecuteScalar(System.Data.IDbCommand command)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDataReader ExecuteReader(System.Data.IDbCommand command)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.DataSet FillDataSet(System.Data.IDbDataAdapter dataAdapter)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.DataSet FillDataSet(System.Collections.Generic.List<System.Data.IDbDataAdapter> dataAdapters)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.DataSet FillDataSet(System.Data.IDbDataAdapter dataAdapter, string tableName)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.DataSet FillDataSet(System.Collections.Generic.List<System.Data.IDbDataAdapter> dataAdapters, System.Collections.Generic.List<string> tables)
        {
            throw new System.NotImplementedException();
        }

        public System.Data.DataTable FillDataTable(System.Data.IDbDataAdapter dataAdapter)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateDataSet(System.Data.IDbDataAdapter dataAdapter, System.Data.DataSet dataSet)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateDataSet(System.Data.IDbDataAdapter dataAdapter, string tableName, System.Data.DataSet dataSet)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateDataSet(System.Collections.Generic.List<System.Data.IDbDataAdapter> dataAdapters, System.Collections.Generic.List<string> tables, System.Data.DataSet dataSet)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateDataTable(System.Data.IDbDataAdapter dataAdapter, System.Data.DataTable dataTable)
        {
            throw new System.NotImplementedException();
        }

        public void UpdateDataRows(System.Data.IDbDataAdapter dataAdapter, System.Data.DataRow[] rows)
        {
            throw new System.NotImplementedException();
        }

        public string ParameterPrefix
        {
            get { throw new System.NotImplementedException(); }
        }

        public string ToDbDateTimeString(System.DateTime dateTime)
        {
            throw new System.NotImplementedException();
        }

        public bool IsDbException(System.Exception exception)
        {
            throw new System.NotImplementedException();
        }

        public string CurrentGmtDateTimeFunction
        {
            get { throw new System.NotImplementedException(); }
        }

        public string CurrentDateTimeFunction
        {
            get { throw new System.NotImplementedException(); }
        }

        public string CurrentDateTimePlusDays(int days)
        {
            throw new System.NotImplementedException();
        }

        public string CurrentDateTimePlusSeconds(int seconds)
        {
            throw new System.NotImplementedException();
        }

        public System.DateTime MinDateTime()
        {
            throw new System.NotImplementedException();
        }

        public System.DateTime MaxDateTime()
        {
            throw new System.NotImplementedException();
        }

        public System.Data.IDbTransaction Transaction
        {
            get { throw new System.NotImplementedException(); }
        }

        public System.Data.IDbTransaction BeginTransaction()
        {
            throw new System.NotImplementedException();
        }

        public void CommitTransaction()
        {
            throw new System.NotImplementedException();
        }

        public void RollbackTransaction()
        {
            throw new System.NotImplementedException();
        }

        public bool CanBulkCopy
        {
            get { throw new System.NotImplementedException(); }
        }

        public long BulkCopy(string sDestinationTable, System.Data.DataTable sourceTable, System.TimeSpan timeout)
        {
            throw new System.NotImplementedException();
        }

        public long BulkCopy(string sDestinationTable, System.Data.DataTable sourceTable, int batchSize, System.TimeSpan timeout)
        {
            throw new System.NotImplementedException();
        }

        public long BulkCopy(string sDestinationTable, System.Data.DataRowCollection rows, System.TimeSpan timeout)
        {
            throw new System.NotImplementedException();
        }

        public long BulkCopy(string sDestinationTable, System.Data.DataRowCollection rows, int batchSize, System.TimeSpan timeout)
        {
            throw new System.NotImplementedException();
        }

        public long BulkCopy(string sDestinationTable, System.Data.IDataReader reader, System.TimeSpan timeout)
        {
            throw new System.NotImplementedException();
        }

        public long BulkCopy(string sDestinationTable, System.Data.IDataReader reader, int batchSize, System.TimeSpan timeout)
        {
            throw new System.NotImplementedException();
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            throw new System.NotImplementedException();
        }

        #endregion

        #region IXmlInitializable Members

        //#region IDbInitializer members
        /* data source={0};initial catalog={1};user id={2};password={3};
         * 
        <database id="sql_server" assembly="SharpObjects.Data" type="SharpObjects.Data.SqlServer2005Db">
                <connection_string is_encrypted="false">Data Source=(local);Initial Catalog=tempdb;User=sa;Password=system;</connection_string>
        </database>
        */
        public void Initialize(System.Xml.XmlElement initializationXmlElement)
        {
            IConfigurationProvider init = new XmlConfigurationProvider(initializationXmlElement);

            this.Id = init.GetString("@id", this.DatabaseBrandAndVersion);

            this.connectionString = init.GetString("connection_string");
            this.connection = new SqlConnection(this.connectionString);

            this.IsInitialized = true;
        }

        public bool IsInitialized { get; set; }

        #endregion

        #region UTILITIES

        protected string[] GetParamNames(IDbParameter[] parameters)
        {
            string[] parameterStrings = new string[parameters.Length];

            for (int k = 0; k < parameters.Length; k++)
            {
                if (parameters[k].IsDirectSqlExpression)
                {
                    parameterStrings[k] = parameters[k].Value.ToString();
                }
                else
                {
                    parameterStrings[k] = this.ParameterPrefix + parameters[k].ToString();
                }
            }

            return parameterStrings;
        }

        protected SqlDbType DbTypeToSqlDbType(DbType dbType)
        {
            switch (dbType)
            {
                case DbType.AnsiString: return SqlDbType.VarChar;
                case DbType.AnsiStringFixedLength: return SqlDbType;
                case DbType.Binary: return SqlDbType;
                case DbType.Boolean: return SqlDbType;
                case DbType.Byte: return SqlDbType;
                case DbType.Currency: return SqlDbType;
                case DbType.Date: return SqlDbType;
                case DbType.DateTime: return SqlDbType;
                case DbType.DateTime2: return SqlDbType;
                case DbType.DateTimeOffset: return SqlDbType;
                case DbType.Decimal: return SqlDbType;
                case DbType.Double: return SqlDbType;
                case DbType.Guid: return SqlDbType;
                case DbType.Int16: return SqlDbType;
                case DbType.Int32: return SqlDbType;
                case DbType.Int64: return SqlDbType;
                case DbType.Object: return SqlDbType;
                case DbType.SByte: return SqlDbType;
                case DbType.Single: return SqlDbType;
                case DbType.String: return SqlDbType;
                case DbType.StringFixedLength: return SqlDbType;
                case DbType.Time: return SqlDbType;
                case DbType.UInt16: return SqlDbType;
                case DbType.UInt32: return SqlDbType;
                case DbType.UInt64: return SqlDbType;
                case DbType.VarNumeric: return SqlDbType;
                case DbType.Xml: return SqlDbType;


                case DbType.Char: return SqlDbType.Char;
                case DbType.UnicodeChar: return SqlDbType.NChar;
                case DbType.AnsiString: return SqlDbType.VarChar;
                case DbType.UnicodeString: return SqlDbType.NVarChar;
                case DbType.AnsiStringFixedLength: return SqlDbType.Char;
                case DbType.UnicodeStringFixedLength: return SqlDbType.NChar;
                case DbType.Text: return SqlDbType.Text;
                case DbType.UnicodeText: return SqlDbType.NText;
                case DbType.Binary: return SqlDbType.Image;
                case DbType.Boolean: return SqlDbType.Bit;
                case DbType.Byte: return SqlDbType.TinyInt;
                case DbType.DateTime: return SqlDbType.DateTime;
                case DbType.Double: return SqlDbType.Float;
                case DbType.Decimal: return SqlDbType.Decimal;
                case DbType.Int: return SqlDbType.Int;
                case DbType.Long: return SqlDbType.BigInt;
                case DbType.Recordset: return SqlDbType.Variant;
                case DbType.UniqueIdentifier: return SqlDbType.UniqueIdentifier;
                case DbType.Xml: return SqlDbType.Xml;

                default: throw new ArgumentException("Unsupported data type", dbType.ToString());
            }
        }


        #endregion // UTILITIES
    }
}